#pragma once

#include "..\\ExternalTools\\ExternalTools.h"

#include "..\\Loirey\\loirey_GLOBAL.h"
#include "..\\Loirey\\loirey_BasicStructure.h"
#include "..\\Loirey\\loirey_AVLTree.h"

#include "cl_base_Data.h"

using namespace loirey;

class CDataSetForBinaryClassification : public CLabeledDataSetForClassification
{
public:
	bool fSetPosIfNonNeg;
	bool fSetNegIfNonPos;
	set<int> LabelSet_Pos;
	set<int> LabelSet_Neg;
	CLabeledDataSetForClassification* pRealDataSet;

public:
	virtual ~CDataSetForBinaryClassification() { }

	virtual int GetExampleAmount();
	virtual double GetExampleInitialWeight(int ExampleIndex);
	virtual int GetFeatureDimension();
	virtual double GetExampleFeature(int ExampleIndex, int FeatureIndex);
	virtual int GetExampleLabel(int ExampleIndex);

	virtual void InitValidFeatures();
	virtual int GetValidFeatureAmount();
	virtual bool IsFeatureValid(int FeatureIndex);
	virtual void UpdateValidFeatures();
public:
	CDataSetForBinaryClassification();
	CDataSetForBinaryClassification(CLabeledDataSetForClassification* pFixedLabeledDataSetForClassification, int TargetLabel);
	virtual void SetRealDataSet(CLabeledDataSetForClassification* pFixedLabeledDataSetForClassification);
public:
	virtual void SetTargetLabel(int TargetLabel);
	virtual void SetPosLabelSet(const CSimpleTypeArray<int>& PosLabelSet);
	virtual void SetNegLabelSet(const CSimpleTypeArray<int>& NegLabelSet);
	virtual void SetPosLabelSetByNonNeg();
	virtual void SetNegLabelSetByNonPos();
	virtual void CopyLabelSettingFrom(const CDataSetForBinaryClassification& Another);
public:
	virtual void InputLabelSettingsFromStream(istream& inStream);
	virtual void OutputLabelSettingsToStream(ostream& outStream) const;
public:
	virtual bool IsLabelPos(int Label);
	virtual bool IsLabelNeg(int Label);
	virtual int GetLabelFlag(int Label);
	virtual bool IsExamplePos(int ExampleIndex);
	virtual bool IsExampleNeg(int ExampleIndex);
	virtual int GetExampleFlag(int ExampleIndex);
};

class CBinaryClassificationResult_ByPrediction
{
public:
	int _PosAmount;
	int _NegAmount;
	int _TruePosAmount;
	int _FalsePosAmount;

	double _PosWeight;
	double _NegWeight;
	double _TruePosWeight;
	double _FalsePosWeight;

	double wErrorRate;
	double wDetectionRate;
	double wFalsePositiveRate;
	double wPrecision;

	double ErrorRate;
	double DetectionRate;
	double FalsePositiveRate;
	double Precision;

	CBinaryClassificationResult_ByPrediction();
	CBinaryClassificationResult_ByPrediction(int PosAmount, int NegAmount, int TruePosAmount, int FalsePosAmount);

	void Clear();

	void NewTest(int Label, int Prediction, double Weight);
	void AddEquals(const CBinaryClassificationResult_ByPrediction& b);
	void SubEquals(const CBinaryClassificationResult_ByPrediction& b);

	void Analyse();
	//void InputFromStream(istream& inStream);
	void OutputToStream_i(ostream& outStream);
	void OutputToStream_w(ostream& outStream);
};

class CBinaryClassificationResult_ByConfidence
{
public:
	int ExtraFalseNegAmount;
	CSimpleTypeArray<double> Pos;
	CSimpleTypeArray<double> Neg;

public:
	CBinaryClassificationResult_ByConfidence();
	void Clear();
	void Analyse();

	int GetTruePosAmount_By_Confidence(double ConfidenceThreshold);
	int GetFalsePosAmount_By_Confidence(double ConfidenceThreshold);

	double Get_ConfidenceThreshold_By_FalsePositiveRate(double FPR);
	bool Get_ConfidenceThreshold_By_Recall(double& dstConfidenceThreshold, double Recall);

	double Get_Precision_By_Confidence(double ConfidenceThreshold);
	double Get_Precision_By_Recall(double Recall);

	double Get_Recall_By_Confidence(double ConfidenceThreshold);
	double Get_Recall_By_FalsePositiveRate(double FPR);

	double Get_AveragePrecision();

	void OutputPRCtoStream(ostream& outStream, int Length, double RecallLow, double RecallHigh, bool fUseLogScale);
	void OutputROCtoStream(ostream& outStream, int Length, double RecallLow, double RecallHigh, bool fUseLogScale);
};

class CBinaryClassificationExampleList
{
public:
	CWeightedClassificationExampleList PosList;
	CWeightedClassificationExampleList NegList;
	
public:
	CBinaryClassificationExampleList();
	virtual void Clear();
	virtual void myInit(CDataSetForBinaryClassification* pDataSet);
	virtual void myInit(CDataSetForBinaryClassification* pDataSet, const CWeightedClassificationExampleList& ExampleList);
	virtual void myInit(const CBinaryClassificationExampleList& Src, double SampleRate = 1.0);
	virtual void myInit(const CBinaryClassificationExampleList& Src, double PosSampleRate, double NegSampleRate);
public:
	virtual void SortByIndex();
	virtual void SortByWeight();
	virtual void MakeMixedList(CWeightedClassificationExampleList& DstExampleList) const;
	virtual void BalanceRelativePosNegTotalWeightRatio(double RelativePosNegWeightRatio = 1.0);
public:
	virtual int GetTotalExampleAmount() const;
	virtual double GetTotalExampleWeight() const;
	virtual void ComputeTotalExampleWeight();
	virtual void NormalizeExampleWeight(double TargetTotalExampleWeight = 1.0);
};

class CBinaryClassifier
{
public:
	virtual ~CBinaryClassifier() { }
protected:
	virtual void _Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction) = 0;
public:
	virtual bool InputFromStream(istream& inStream) = 0;
	virtual void OutputToStream(ostream& outStream) = 0;
	virtual void SaveToFile(string strFN_dstModel);
	virtual bool LoadFromFile(string strFN_srcModel);
public:
	virtual void Classify(CDataSetForClassification* pDataSet, int ExampleIndex, double& DstConfidence, int& DstPrediction);
	virtual void Classify(CSingleDataForClassification* pSingleData, double& DstConfidence, int& DstPrediction);
	virtual double Classify(CDataSetForClassification* pDataSet, int ExampleIndex);
	virtual double Classify(CSingleDataForClassification* pSingleData);
	virtual void Classify(
		CDataSetForClassification* pDataSet, CBinaryClassificationExampleList& BinaryExampleList,
		CBinaryClassificationResult_ByConfidence& DstResult_ByConfidence,
		CBinaryClassificationResult_ByPrediction& DstResult_ByPrediction);
	virtual void Classify(
		CDataSetForBinaryClassification* pBinaryDataSet, CWeightedClassificationExampleList& ExampleList,
		CBinaryClassificationResult_ByConfidence& DstResult_ByConfidence,
		CBinaryClassificationResult_ByPrediction& DstResult_ByPrediction);
};

